#ifndef __WIZ_THREAD_TLS_HPP__SHANHAOBO_19800429__
#define __WIZ_THREAD_TLS_HPP__SHANHAOBO_19800429__

#include "../../Base/WizBase.hpp"
#include "../../Core/Memory/WizMemory.hpp"

#include "../../DataType/SmartPtr/SharedPtr/WizDataTypeSharedPtr.hpp"

#include "../WizAtomicCount.hpp"

namespace Wiz
{
    namespace Thread
    {
        //////////////////////////////////////////////////////////////////////////
        /// Thread Local Store
        namespace TLS
        {
            namespace CleanUpFunction
            {
                struct Type
                {
                    virtual ~Type()
                    {}

                    virtual ::Wiz::Void::Type operator()(::Wiz::Void::Ptr data) = 0;
                };
                typedef ::Wiz::SharedPtr::Type<::Wiz::Thread::TLS::CleanUpFunction::Type>   SharedPtr;
            } /// end of namespace CleanUpFunction

            WIZ_EXPORT ::Wiz::Void::Type SetData(
                ::Wiz::Void::ConstPtr                           Key,
                ::Wiz::Thread::TLS::CleanUpFunction::SharedPtr  func,
                ::Wiz::Void::Ptr                                TLSDataPtr,
                ::Wiz::Bool::Type                               CleanUpExisting
            );
            WIZ_EXPORT ::Wiz::Void::Ptr GetData(::Wiz::Void::ConstPtr Key);

            template <class ElementT>
            class Type /// Fixed Me : ::Wiz::Noncopyable::Type
            {
                typedef ElementT            tElement;
                typedef tElement&           tElementRef;
                typedef tElement*           tElementPtr;
                typedef tElement* const     tElementFixedPtr;
            protected:
                typedef ::Wiz::Void::Type (*tCleanUpFuncPtr)(tElementPtr);
            private:
                struct StdCleanUp_t : ::Wiz::Thread::TLS::CleanUpFunction::Type
                {
                    ::Wiz::Void::Type operator()(::Wiz::Void::Ptr data)
                    {
                        delete ::Wiz::Cast::Static<ElementT*>(data);
                    }
                };
                struct CustomCleanUp_t : ::Wiz::Thread::TLS::CleanUpFunction::Type
                {
                    tCleanUpFuncPtr m_CleanUpFuncPtr;

                    explicit CustomCleanUp_t(tCleanUpFuncPtr CUFPtr) : m_CleanUpFuncPtr(CUFPtr)
                    {}
                    ::Wiz::Void::Type operator()(::Wiz::Void::Ptr data)
                    {
                        m_CleanUpFuncPtr(::Wiz::Cast::Static<ElementT*>(data));
                    }
                };
                typedef ::Wiz::Memory::NewDeletePair::Type<::Wiz::Memory::Allocator::Heap::Type, StdCleanUp_t()>                    tStdNewDeletePair;
                typedef ::Wiz::Memory::NewDeletePair::Type<::Wiz::Memory::Allocator::Heap::Type, CustomCleanUp_t(tCleanUpFuncPtr)>  tCustomNewDeletePair;
            public:
                Type() : m_CleanUp(tStdNewDeletePair::New(), tStdNewDeletePair::tDelete())
                {}
                explicit Type(tCleanUpFuncPtr FuncPtr)
                {
                    if (::Wiz::IsValidPtr(FuncPtr))
                    {
                        m_CleanUp.Reset(tCustomNewDeletePair::New(FuncPtr), tCustomNewDeletePair::tDelete());
                    }
                }
                ~Type()
                {
                    Reset();
                }
                ::Wiz::Bool::Type IsValid()
                {
                    return ::Wiz::IsValidPtr(this->GetData());
                }
                ::Wiz::Bool::Type NotValid()
                {
                    return IsValid() == ::Wiz::Bool::False;
                }
                tElementPtr GetData() const
                {
                    return static_cast<tElementPtr>(::Wiz::Thread::TLS::GetData(this));
                }
                tElementPtr operator->() const
                {
                    return this->GetData();
                }
                tElementRef operator*() const
                {
                    return *(this->GetData());
                }
                tElementPtr Release()
                {
                    tElementFixedPtr Temp = this->GetData();
                    ::Wiz::Thread::TLS::SetData(this, ::Wiz::Thread::TLS::CleanUpFunction::SharedPtr(), WIZ_NULLPTR, ::Wiz::Bool::False);
                    return Temp;
                }
                ::Wiz::Void::Type Reset(tElementPtr NewVal = WIZ_NULLPTR)
                {
                    tElementFixedPtr CurrVal = this->GetData();
                    if( CurrVal != NewVal)
                    {
                        ::Wiz::Thread::TLS::SetData(this, m_CleanUp, NewVal, ::Wiz::Bool::True);
                    }
                }
            protected:
                ::Wiz::Thread::TLS::CleanUpFunction::SharedPtr      m_CleanUp;
            };
        } /// end of namespace TLS
        //////////////////////////////////////////////////////////////////////////
    } /// end of namespace Thread
} /// end of namespace Wiz

#endif /*__WIZ_THREAD_TLS_HPP__SHANHAOBO_19800429__*/
